#include "scene.h"

#include "item/circleitem.h"
#include "item/circulararcitem.h"
#include "item/ellipseitem.h"
#include "item/ellipticalarcitem.h"
#include "item/rectangleitem.h"
#include "item/polylineitem.h"
#include "item/polygonitem.h"

#include "xdl/symbol.h"

#include <QPainter>

namespace SymbolEditor
{

    Scene::Scene(QObject *parent):
        LeGraphicsView::Scene(parent)
    {
    }

    Scene::~Scene()
    {
    }

    QList<GraphicsItem *> Scene::selectedObjects()
    {
        QList<GraphicsItem *> objects;
        for (auto item : selectedItems())
        {
            auto *object = dynamic_cast<GraphicsItem *>(item);
            if (object != nullptr)
            {
                objects.append(object);
            }
        }
        return objects;
    }

    GraphicsItem *Scene::itemForDocumentId(quint64 id) const
    {
        return m_itemMap.value(id);
    }

    quint64 Scene::documentIdForItem(GraphicsItem *item) const
    {
        return m_itemMap.key(item);
    }

    QList<GraphicsItem *> Scene::documentItems(const QPainterPath &path, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape,
                                               Qt::SortOrder order = Qt::DescendingOrder)
    {
        QList<GraphicsItem *> result;

        for (const auto item: items(path, mode, order))
        {
            if (item->type() < GraphicsItem::ModelType)
            {
                continue;
            }
            result.append(static_cast<GraphicsItem*>(item));
        }

        return result;
    }

    GraphicsItem *Scene::lowestObscuringItem(GraphicsItem *item)
    {
        auto path = item->mapToScene(item->shape());
        auto items = documentItems(path, Qt::IntersectsItemShape, Qt::AscendingOrder);
        Q_ASSERT(items.contains(item));

        if (item == items.last())
        {
            return nullptr;
        }
        else
        {
            return items.at(items.indexOf(item) + 1);
        }
    }

    GraphicsItem *Scene::highestObscuringItem(GraphicsItem *item)
    {
        auto path = item->mapToScene(item->shape());
        auto items = documentItems(path, Qt::IntersectsItemShape, Qt::AscendingOrder);
        Q_ASSERT(items.contains(item));

        if (item == items.last())
        {
            return nullptr;
        }
        else
        {
            return items.last();
        }
    }

    GraphicsItem *Scene::highestObscuredItem(GraphicsItem *item)
    {
        auto path = item->mapToScene(item->shape());
        auto items = documentItems(path, Qt::IntersectsItemShape, Qt::AscendingOrder);
        Q_ASSERT(items.contains(item));

        if (item == items.first())
        {
            return nullptr;
        }
        else
        {
            return items.at(items.indexOf(item) - 1);
        }
    }

    GraphicsItem *Scene::lowestObscuredItem(GraphicsItem *item)
    {
        auto path = item->mapToScene(item->shape());
        auto items = documentItems(path, Qt::IntersectsItemShape, Qt::AscendingOrder);
        Q_ASSERT(items.contains(item));

        if (item == items.first())
        {
            return nullptr;
        }
        else
        {
            return items.first();
        }
    }

    // FIXME
//    void Scene::setPalette(Palette palette)
//    {
//        m_palette = palette;
//        for (auto  item: m_itemMap.values())
//        {
//            item->setPalette(m_palette);
//        }
//    }

    void Scene::addDocumentItem(quint64 id, const Item *docItem)
    {
        GraphicsItem *sceneItem;
        switch (docItem->type())
        {
            case Rectangle:
                sceneItem = new GraphicsRectangleItem();
                break;
            case Circle:
                sceneItem = new GraphicsCircleItem;
                break;
            case CircularArc:
                sceneItem = new GraphicsCircularArcItem;
                break;
            case Ellipse:
                sceneItem = new GraphicsEllipseItem;
                break;
            case EllipticalArc:
                sceneItem = new GraphicsEllipticalArcItem;
                break;
            case Polyline:
                sceneItem = new GraphicsPolylineItem;
                break;
            case Polygon:
                sceneItem = new GraphicsPolygonItem;
                break;
            case Label:
                // FIXME
                return;
            case Pin:
                // FIXME
                return;
            case Group:
                // FIXME
                return;
            default:
                return;
        }

        for (auto propId: docItem->propertyIdList())
        {
            sceneItem->setProperty(propId, docItem->property(propId));
        }

        sceneItem->setData(0, QVariant::fromValue<quint64>(id));
        sceneItem->setPalette(palette()); // FIXME

        m_itemMap.insert(id, sceneItem);
        addItem(sceneItem);
    }

    void Scene::updateDocumentItemProperty(quint64 itemId, quint64 propertyId, const QVariant &value)
    {
        auto item = itemForDocumentId(itemId);
        if (item == nullptr)
        {
            return;
        }
        item->setProperty(PropertyId(propertyId), value); // FIXME
    }

    void Scene::removeDocumentItem(quint64 id)
    {
        if (!m_itemMap.contains(id))
        {
            return;
        }

        auto sceneItem = m_itemMap.value(id);
        removeItem(sceneItem);
        delete sceneItem;
    }

    QPen Scene::makePen(const Item *item)
    {
        QPen pen;
        pen.setStyle(Qt::PenStyle(item->lineStyle()));
        qreal width = SymbolEditor::MediumLine;
        switch (item->lineWidth())
        {
            case SymbolEditor::ThinestLine:
                width = 0.13;
                break;
            case SymbolEditor::ThinerLine:
                width = 0.18;
                break;
            case SymbolEditor::ThinLine:
                width = 0.25;
                break;
            case SymbolEditor::SlightlyThinLine:
                width = 0.35;
                break;
            case SymbolEditor::MediumLine:
                width = 0.50;
                break;
            case SymbolEditor::SlightlyThickLine:
                width = 0.70;
                break;
            case SymbolEditor::ThickLine:
                width = 1.0;
                break;
            case SymbolEditor::ThickerLine:
                width = 1.40;
                break;
            case SymbolEditor::ThickestLine:
                width = 2.00;
                break;
        }
        pen.setWidthF(width);
        return pen;
    }

    QBrush Scene::makeBrush(const Item *item)
    {
        QBrush brush;
        brush.setStyle(Qt::SolidPattern);
        brush.setColor(item->fillColor());
        return brush;
    }

}
